﻿using Casamiel.Domain;
using Smooth.IoC.Repository.UnitOfWork;
using Smooth.IoC.Repository.UnitOfWork.Extensions;
using Smooth.IoC.UnitOfWork.Interfaces;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Dapper;
using System.Linq;

namespace Casamiel.Infrastructure
{
	public abstract class BaseRepository<TEntity, TPk> : Repository<TEntity, TPk>, IRepositoryExt<TEntity, TPk> where TEntity : class where TPk : IComparable
	{
		/// <summary>
		/// 
		/// </summary>
		/// <param name="factory"></param>
		protected BaseRepository(IDbFactory factory) : base(factory)
		{
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="entity"></param>
		/// <param name="uow"></param>
		public virtual void Save(TEntity entity, IUnitOfWork uow)
		{
			uow.Insert(entity);
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="entity"></param>
		/// <param name="uow"></param>
		/// <returns></returns>
		public virtual async Task SaveAsync(TEntity entity, IUnitOfWork uow)
		{
			await uow.InsertAsync(entity).ConfigureAwait(true);
		}

		
		/// <summary>
		/// Gets the list by page.
		/// </summary>
		/// <returns>The list by page.</returns>
		/// <param name="pageIndex">Page index.</param>
		/// <param name="pageSize">Page size.</param>
		/// <param name="sqlwhere">Sqlwhere.</param>
		/// <param name="orderby">Orderby.</param>
		/// <typeparam name="TSession">The 1st type parameter.</typeparam>
		public virtual async Task<PagingResult<TEntity>> GetListAsync<TSession>(int pageIndex, int pageSize, string sqlwhere, string orderby) where TSession : class, ISession
		{
		 
			PagingResult<TEntity> result = new PagingResult<TEntity>
			{
				PageIndex = pageIndex,
				PageSize = pageSize
			};
			int total = 0;
			using (var session = Factory.Create<TSession>())
			{
				var sql = GetSelectSQL($"{Sql.Table<TEntity>(session.SqlDialect)}", sqlwhere, orderby, pageIndex, pageSize);
				string countsql = $"select count(0) from {Sql.Table<TEntity>(session.SqlDialect)}";
				if (!string.IsNullOrEmpty(sqlwhere))
				{
					countsql += " where " + sqlwhere;
				}
				//var m = await session.QueryMultipleAsync(countsql + ";" + sql.Item1,new { begin=sql.Item2, end=sql.Item3 } ).ConfigureAwait(false);

				//var m = await session.QueryMultipleAsync(countsql +";"+ sql).ConfigureAwait(false);
                //Console.WriteLine(countsql + sql);
                //total = m.Read<int>().SingleOrDefault();
                //var list1 = m.Read<TEntity>().ToList();
				total = await session.QuerySingleOrDefaultAsync<int>(countsql).ConfigureAwait(false );
				var list = await session.QueryAsync<TEntity>(sql.Item1, new { begin = sql.Item2, end = sql.Item3 }).ConfigureAwait(false);
				result.Data = list.ToList();
				result.Total = total;
                //result.Raw = countsql + sql;
			}
			return result;
		}
        internal string GetCountSQL(string tablename, string sqlwhere)
        {
            string sql = " count(*)";
            //if (this.isDistinct)
            //{
            //  sql = "DISTINCT " + sql;
            //}
            SelectBuilder builder = new SelectBuilder();

            builder.Select(sql).From(tablename);
            if (sqlwhere.Length > 0)
            {
                builder.Where(sqlwhere);
            }
             
            return builder.GetSqlForSelectBuilder(builder.Data);
        }
        internal Tuple<string,int,int> GetSelectSQL(string tablename, string sqlwhere, string orderby, int pageIndex = 0, int pageSize = 0)
		{
			string sql = "*";
			//if (this.isDistinct)
			//{
			//	sql = "DISTINCT " + sql;
			//}
			SelectBuilder builder = new SelectBuilder();
			builder.Select(sql).From(tablename);
			if (sqlwhere.Length > 0)
			{
				builder.Where(sqlwhere);
			}
			//if (!string.IsNullOrEmpty(this.groupByExp))
			//{
			//	builder.GroupBy(this.groupByExp);
			//}
			//if (this.sbHaving.Length > 0)
			//{
			//	builder.Having(this.sbHaving.ToString());
			//}
			//if (!string.IsNullOrEmpty(this.orderByExp))
			//{
			builder.OrderBy(orderby);
			//}
			//else
			//{
			//	builder.OrderBy(this.PKColumn.FullName);
			//}
			builder.Paging(pageIndex, pageSize);
			var sql1 = builder.GetSqlForSelectBuilder(builder.Data);
			int a = builder.Data.GetFromItems();
			int b = builder.Data.GetToItems();
			return new Tuple<string,int,int>(sql1,a,b);
		}

		public virtual void Save<TSession>(TEntity entity) where TSession : class, ISession
		{
			using (var uow = Factory.Create<IUnitOfWork, TSession>())
			{
				Save(entity, uow);
			}
		}

		public virtual async Task SaveAsync<TSession>(TEntity entity) where TSession : class, ISession
		{
			using (var uow = Factory.Create<IUnitOfWork, TSession>())
			{
				await SaveAsync(entity, uow).ConfigureAwait(false);
			}
		}
		public virtual bool Update(TEntity entity, IUnitOfWork uow)
		{
			return uow.Update(entity);
		}
		public virtual async Task<bool> UpdateAsync(TEntity entity, IUnitOfWork uow)
		{
			return await uow.UpdateAsync(entity).ConfigureAwait(true);
		}

		public virtual bool Update<TSession>(TEntity entity) where TSession : class, ISession
		{
			bool sucess = false;
			using (var uow = Factory.Create<IUnitOfWork, TSession>())
			{
				sucess = uow.Update(entity);
			}
			return sucess;
		}

		public virtual async Task<bool> UpdateAsync<TSession>(TEntity entity) where TSession : class, ISession
		{
			bool sucess = false;
			using (var uow = Factory.Create<IUnitOfWork, TSession>())
			{
				sucess = await uow.UpdateAsync(entity).ConfigureAwait(false);
			}
			return sucess;
		}
	}
}
